﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
using Orleans.Runtime;
using Orleans.Storage;
using Sample.GrainService;
using Sample.Implements;
using System.Threading.Tasks;

namespace Service
{

    // !!!  Microsoft.Orleans.Clustering.AdoNet

    public class OrleansServiceHelper
    {
        private const string Invariant = "System.Data.SqlClient";


        private OrleansServiceBuilderContext BuilderContext { get; set; }

        public OrleansServiceHelper(OrleansServiceBuilderContext context) {
            this.BuilderContext = context;
        }

        /// <summary>
        /// Builder
        /// </summary>
        /// <returns></returns>
        private ISiloHost SiloHostBuild()
        {
            var builder = new SiloHostBuilder();

            // 配置监听端口
            builder.ConfigureEndpoints(
                siloPort: this.BuilderContext.SiloPort,
                gatewayPort: this.BuilderContext.GatewayPort);

            // 集群配置
            builder.Configure<ClusterOptions>(options =>
            {
                options.ClusterId = this.BuilderContext.ClusterId;
                options.ServiceId = this.BuilderContext.ServiceId;
            });

            // Zookeeper 配置集群
            // Microsoft.Orleans.OrleansZooKeeperUtils
            builder.UseZooKeeperClustering(option =>
            {
                option.Configure(a =>
                {
                    a.ConnectionString = this.BuilderContext.ZookeeperConnectionString;
                });
            });

            // 新增状态存储方案
            // Microsoft.Orleans.OrleansSQLUtils
            builder.AddAdoNetGrainStorage("OrleaneStorage", options =>
            {
                options.ConnectionString = this.BuilderContext.MSSQLConnectionString;
                options.Invariant = Invariant;
                options.UseJsonFormat = true;
            });

            // 类型存储方案
            //IServiceProviderFactory<IStorageProvider> factory = new ServiceContainer(); //new UserServiceStorgeProvider();
            //builder.UseServiceProviderFactory<IStorageProvider>(factory);
            builder.ConfigureServices(services =>
            {

                services.AddSingletonNamedService("UserServiceStorgeProvider", (s, n) =>
                {
                    return (IGrainStorage)ActivatorUtilities.CreateInstance<UserServiceStorgeProvider>(s);
                });

                services.AddSingletonNamedService("UserServiceStorgeProvider",
                    (s, n) => (ILifecycleParticipant<ISiloLifecycle>)s.GetRequiredServiceByName<IGrainStorage>(n));

                //services.TryAddSingleton(sp => sp.GetServiceByName<IStorageProvider>("UserServiceStorgeProvider"));

            });

            // 添加服务
            // 
            builder.ConfigureServices(services => {
                services.AddSingleton<IDataService, DataService>();
                services.AddSingleton<IDataServiceClient, DataServiceClient>();
                services.AddSingleton<ITest, Test>();
            });

            // Dashboard
            if (this.BuilderContext.IsUseDashboard)
            {
                System.Console.WriteLine("***** Use Dashboard ******");

                builder.UseDashboard(options =>
                {
                    options.Username = this.BuilderContext.DashboardContext.Username;
                    options.Password = this.BuilderContext.DashboardContext.Password;
                    options.Port = this.BuilderContext.DashboardContext.Port;
                    options.Host = "127.0.0.1";
                });
            }


            // 使用MSSQL配置集群
            //Microsoft.Orleans.Clustering.AdoNet
            //builder.UseAdoNetClustering(options =>
            //{
            //    options.Invariant = "System.Data.SqlClient";
            //    options.ConnectionString = "ConnectionString";
            //});


            builder.ConfigureApplicationParts(parts =>
            {

                parts.AddFromApplicationBaseDirectory();
                //parts
                //    .AddApplicationPart(typeof(UserService).Assembly).WithReferences();

                //parts.AddApplicationPart(typeof(IUserService).Assembly).WithReferences();

            });

            builder.ConfigureLogging(logger =>
            {
                logger.AddConsole().SetMinimumLevel(LogLevel.Information);
            });

            ISiloHost iSiloHost = builder.Build();

            return iSiloHost;


        }

        /// <summary>
        /// 启动服务
        /// </summary>
        /// <returns></returns>
        public async Task<ISiloHost> StartAsync()
        {
            var iSiloHost = this.SiloHostBuild();

            await iSiloHost.StartAsync();

            return iSiloHost;
        }

    }
}
